package org.dht.com.tra;

import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;
import org.dht.com.conf.CommunicationProperties;

/**
 * The {@code ComunicationManagerCache} class is used to create
 * CommunicationManagerWaitingResult and have centralized access these instances
 * 
 * @see CommunicationManagerWaitingResult
 * @see CommunicationManagerStructure
 * @see CommunicationManagerNetworkLAN
 * @see CommunicationManagerTCP
 * @see CommunicationManagerUDP
 * @see CommunicationManager
 */
public class CommunicationManagerCache {

	/**
	 * Logger
	 */
	private static final Logger logger = Logger
			.getLogger(CommunicationManagerCache.class);

	/**
	 * Map of instances of communication manager
	 */
	private static Map<String, CommunicationManager> communicationManagers;

	/**
	 * Builds an CommunicationManagerCache
	 */
	private CommunicationManagerCache() {
		communicationManagers = new HashMap<String, CommunicationManager>();
	}

	/**
	 * Gets the single instance of the communication manager.
	 * 
	 * @return The single instance of the {@link CommunicationManagert}
	 */

	public static CommunicationManager createCommunicationManager(
			String instanceName, CommunicationProperties communicationProperties) {

		if (communicationManagers == null) {
			communicationManagers = new HashMap<String, CommunicationManager>();
		}
		if (communicationManagers.containsKey(instanceName)) {

			communicationProperties.getParams().put(
					"RESPONSE_TIME",
					String.valueOf(communicationProperties.getTime()
							.getWaitingResult()));

			communicationManagers.get(instanceName).setCommunicationProperties(
					communicationProperties.getParams());

			logger.warn("Changed properties of '" + instanceName + "'");

			return communicationManagers.get(instanceName);
		}

		CommunicationManagerWaitingResult communicationManagerWaitingResult = null;
		Class<?> classIn;

		try {

			classIn = Class.forName(communicationProperties.getInstance()
					.getClazz());
			communicationManagerWaitingResult = (CommunicationManagerWaitingResult) classIn
					.newInstance();

			communicationProperties.getParams().put(
					"RESPONSE_TIME",
					String.valueOf(communicationProperties.getTime()
							.getWaitingResult()));

			communicationManagerWaitingResult
					.setCommunicationProperties(communicationProperties
							.getParams());

			communicationManagerWaitingResult.init();

			communicationManagers.put(instanceName,
					communicationManagerWaitingResult);

		} catch (ClassNotFoundException e) {
			CommunicationManagerException exception = new CommunicationManagerException(
					"Class not bound ", e);
			logger.fatal("Class not bound ", exception);
		} catch (InstantiationException e) {
			CommunicationManagerException exception = new CommunicationManagerException(
					"Error instantiating class ", e);
			logger.fatal("Error instantiating class", exception);
		} catch (IllegalAccessException e) {
			CommunicationManagerException exception = new CommunicationManagerException(
					"Permission error ", e);
			logger.fatal("Permission error ", exception);
		} catch (ClassCastException e) {
			CommunicationManagerException exception = new CommunicationManagerException(
					"The class '"
							+ communicationProperties.getInstance().getClazz()
							+ "' is not instance of "
							+ CommunicationManager.class.getName(), e);
			logger.fatal(e.getMessage(), exception);
		}

		return communicationManagerWaitingResult;

	}

	/**
	 * Gets instance of CommunicationManager by instance name
	 * 
	 * @param instanceName
	 *            Instance name
	 * @return CommunicationManager instance
	 */
	public static CommunicationManager getCommunicationManager(
			String instanceName) {

		return communicationManagers.get(instanceName);
	}
}
